package cumeo89.chii.client.undo;

import cumeo89.chii.client.util.MyChangeListener;
import cumeo89.chii.client.util.MyChangeListenerCollection;

public class UndoManager implements UndoableEditListener {

	private static final int CAPABILITY = 20;

	private int f = 0, l = 1, p = 0;
	private UndoableEdit[] edits = new UndoableEdit[CAPABILITY + 1];
	private MyChangeListenerCollection listeners = new MyChangeListenerCollection();

	public void add(UndoableEdit edit) {
		if (edit == null) {
			return;
		}
		p = (p + 1) % CAPABILITY;
		edits[p] = edit;
		l = (p + 1) % CAPABILITY;
		if (l == f) {
			edits[f] = null;
			f = (f + 1) % CAPABILITY;
		}

		listeners.fireChange(this);
	}

	public UndoableEdit undo() {
		if (!canUndo()) {
			return null;
		}

		UndoableEdit cmd = edits[p];
		cmd.undo();
		p = (p - 1) % CAPABILITY;

		listeners.fireChange(this);

		return cmd;
	}

	public UndoableEdit redo() {
		if (!canRedo()) {
			return null;
		}

		int t = (p + 1) % CAPABILITY;
		UndoableEdit cmd = edits[t];
		cmd.redo();
		p = t;

		listeners.fireChange(this);

		return cmd;
	}

	public boolean canUndo() {
		return f != p;
	}

	public boolean canRedo() {
		return l != (p + 1) % CAPABILITY;
	}

	public void addChangeListener(MyChangeListener lis) {
		if (!listeners.contains(lis)) {
			listeners.add(lis);
		}
	}

	public boolean removeMyChangeListener(MyChangeListener lis) {
		return listeners.remove(lis);
	}

	public MyChangeListener[] getMyChangeListeners() {
		return (MyChangeListener[]) listeners.toArray();
	}

	public void undoableEditHappened(Object source, UndoableEdit edit) {
		add(edit);
	}

}
